﻿#include "../include/Mmap.h"

#ifdef __linux__

Mmap::Mmap(const std::string path)
{
    _fd = open(path.c_str(), O_RDWR | O_CREAT, 0664);
    if (_fd == -1)
    {
        exit(-1);  
    }


    //获取属性
    fstat(_fd, &_attribute);
    _size = _attribute.st_size;

    //扩容
    size_t newSize = (_size / PAGEVALUE + 1) * PAGEVALUE;
    if (ftruncate(_fd, newSize) == -1)
    {
        
    }
    _capacity = newSize;
    
    //建立映射
    _start = (char*)mmap(nullptr, _capacity, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);

}

bool Mmap::expansion(size_t size)
{
   if (_size + size <= _capacity)
   {
        return true;
   }

    //扩容
   size_t newSize = ((_size + size) / PAGEVALUE + 1) * PAGEVALUE;
    if (ftruncate(_fd, newSize) == -1)
    {
        return false;
    }

    _start = (char*)mremap(_start, _capacity, newSize, MREMAP_MAYMOVE);
    _capacity = newSize;

    return true;
}

Mmap::~Mmap()
{
    if (_start && _start != MAP_FAILED) 
    {
        msync(_start, _size, MS_SYNC);
    }

    if (munmap(_start, _capacity) == -1)
    {
        exit(-1);
    }

    if (ftruncate(_fd, _size) == -1)
    {
        exit(-1);
    }

    close(_fd);
}

#elif defined(_WIN32)

Mmap::Mmap(const std::string path)
{
    _fd = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
        0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (_fd == INVALID_HANDLE_VALUE)
    {
        exit(-1);
    }

    // 获取文件大小
    LARGE_INTEGER fileSize;
    if (!GetFileSizeEx(_fd, &fileSize))  // 修正：使用 GetFileSizeEx
    {
        CloseHandle(_fd);
        exit(-1);
    }
    _size = fileSize.QuadPart;

    // 计算新容量
    LARGE_INTEGER newCapacity;
    newCapacity.QuadPart = (_size / PAGEVALUE + 1) * PAGEVALUE;
    _capacity = newCapacity.QuadPart;

    // 设置文件大小
    if (SetFilePointerEx(_fd, newCapacity, NULL, FILE_BEGIN) == 0)  
    {
        CloseHandle(_fd);
        exit(-1);
    }

    if (!SetEndOfFile(_fd))  
    {
        CloseHandle(_fd);
        exit(-1);
    }
    // 创建文件映射
    
    _mmap = CreateFileMapping(_fd, nullptr, PAGE_READWRITE,
        newCapacity.HighPart, newCapacity.LowPart, nullptr); 
    if (_mmap == nullptr)
    {
        CloseHandle(_fd);
        exit(-1);
    }

    // 映射视图
    _start = static_cast<char*>(MapViewOfFile(_mmap, FILE_MAP_ALL_ACCESS, 0, 0, 0));
    if (_start == nullptr)
    {
        CloseHandle(_mmap);
        CloseHandle(_fd);
        exit(-1);
    }
}

bool Mmap::expansion(size_t size)
{
    if (_size + size <= _capacity)
    {
        return true;
    }

    // 取消当前映射
    if (!UnmapViewOfFile(_start) || !CloseHandle(_mmap))
    {
        return false;
    }

    // 计算新容量
    LARGE_INTEGER newCapacity;
    newCapacity.QuadPart = (((_size + size)) * 2 / PAGEVALUE + 1) * PAGEVALUE;

    // 设置文件指针并扩展文件
    if (SetFilePointerEx(_fd, newCapacity, NULL, FILE_BEGIN) == 0)
    {
        return false;
    }

    if (!SetEndOfFile(_fd))
    {
        return false;
    }

    _capacity = newCapacity.QuadPart;

    // 重新创建映射
    _mmap = CreateFileMapping(_fd, nullptr, PAGE_READWRITE,
        newCapacity.HighPart, newCapacity.LowPart, nullptr);
    if (_mmap == NULL)
    {
        return false;
    }

    _start = static_cast<char*>(MapViewOfFile(_mmap, FILE_MAP_ALL_ACCESS, 0, 0, 0));
    if (_start == nullptr)
    {
        CloseHandle(_mmap);
        return false;
    }

    return true;
}

Mmap::~Mmap()
{
    if (_start != nullptr)
    {
        FlushViewOfFile(_start, _size);
        UnmapViewOfFile(_start);
    }

    if (_mmap != NULL)
    {
        CloseHandle(_mmap);
    }

    // 恢复文件实际大小
    LARGE_INTEGER actualSize;
    actualSize.QuadPart = _size;
    if (SetFilePointerEx(_fd, actualSize, NULL, FILE_BEGIN) && SetEndOfFile(_fd))
    {
        
    }

    if (_fd != INVALID_HANDLE_VALUE)
    {
        CloseHandle(_fd);
    }
}

#endif

ll Mmap::size()
{
    return _size;
}

ll Mmap::capacity()
{
    return _capacity;
}

std::string Mmap::read(size_t start, size_t end)
{
    if (start < 0 || end <= start || start >= _size)
    {
        return "";
    }

    end = std::min(end, _size);
    std::string ans(_start + start, end - start);
    return ans;
}

bool Mmap::write(const std::string& writeContent)
{
    ll n = writeContent.size();
    if (!expansion(n))
    {
        return false;
    }

    memcpy(_start + _size, writeContent.c_str(), n);
    _size += n;
    
    return true;
}

bool Mmap::clear()
{
    _size = 0;
    return true;
}
